﻿using System.Collections.Generic;
using System.Text;
using System.IO;
using Newtonsoft.Json;
using System.Text.RegularExpressions;
using ValidationFramework.Web.MVC.Interfaces;

namespace ValidationFramework.Web.MVC
{
	/// <summary>
	/// Handles the generation of JQuery compliant javascript.
	/// </summary>
	/// <remarks>
	/// For the creation of html client side validation.
	/// </remarks>
	public class JQueryGenerator : IClientValidationGenerator
	{
	    readonly IRuleConverter converter;

		/// <summary>
		/// Initializes a new instance of the JQueryGenerator class.
		/// </summary>
		/// <param name="_strategy"></param>
		public JQueryGenerator(IRuleConverter converter)
		{
			this.converter = converter;
		}

		// writing rules options
		private void WriteRules(JsonWriter writer, FormRuleDictionary formRules)
		{
			
			writer.WriteStartObject();
			foreach (var item in formRules)
			{
				WriteElementRules(writer, item.Key, item.Value);
			}
			writer.WriteEndObject();
		}
		private void WriteElementRules(JsonWriter writer, string elementId, IList<IElementRule> elementRules)
		{
			writer.WritePropertyName(elementId);
			writer.WriteStartObject();
			foreach (var clientRule in elementRules)
			{
				WriteElementRule(writer, clientRule.FunctionName, clientRule.Arguments);
			}
			writer.WriteEndObject();		
		}
		private void WriteElementRule(JsonWriter writer, string functionName, object[] arguments)
		{
			writer.WritePropertyName(functionName);
			var originalFormatting = writer.Formatting;
			writer.Formatting = Formatting.None;

			writer.WriteStartArray();
			foreach (var argument in arguments)
			{
				writer.WriteValue(argument);
			}
			writer.WriteEndArray();

			writer.Formatting = originalFormatting;
		}

		// writing message options
        private void WriteMessages(JsonWriter writer, FormRuleDictionary formRules)
		{
			writer.WriteStartObject();
			foreach (var item in formRules)
			{
				WriteElementRuleMessages(writer, item.Key, item.Value);
			}
			writer.WriteEndObject();
		}		
		private void WriteElementRuleMessages(JsonWriter writer, string elementId, IList<IElementRule> elementRules)
		{
			writer.WritePropertyName(elementId);
			writer.WriteStartObject();
			foreach (var clientRule in elementRules)
			{
				writer.WritePropertyName(clientRule.FunctionName);
				writer.WriteValue(clientRule.ErrorMessage);
			}
			writer.WriteEndObject();			
		}
        
		public string GenerateRuleAndMessageOptions(FormRuleDictionary formRules)
		{
			var stringBuilder = new StringBuilder();
		    using (var stringWriter = new StringWriter(stringBuilder))
		    {
		        using (JsonWriter writer = new JsonTextWriter(stringWriter))
		        {
		            writer.Formatting = Formatting.Indented;
					writer.WriteRaw("rules:");
		            WriteRules(writer, formRules);
		            // json.net isn't separating these 2 properties, do it by hand
		            writer.WriteRaw(",\n");
					writer.WriteRaw("messages:");
		            WriteMessages(writer, formRules);
		        }
		    }

		    return stringBuilder.ToString();
		}

		#region IClientRuleGenerator Members

		public string Generate(string formId, IList<PropertyRuleInfo> rules)
		{
			if (converter == null)
			{
			    return string.Empty;
			}

			var formRules = converter.ConvertToClientRules(rules);

			if (formRules.Count <= 0)
			{
			    return string.Empty;
			}

			// start out with template
			var script = scriptTemplate;

			// fill in template
			script = Regex.Replace(script, "%FormId%", formId);
			script = Regex.Replace(script, "%RulesAndMessages%", GenerateRuleAndMessageOptions(formRules));
			return script;
		}

		#endregion

		// JQuery script template with values supporting MVC Preview 5 defaults
		const string scriptTemplate = @"
// Generated by the .Net Validation Framework
$().ready(function() {

$('#%FormId%').validate({
errorContainer: $('validation-summary-message'),
errorLabelContainer: 'ul.validation-summary-errors',
errorClass:'input-validation-error',
wrapper: 'li',
%RulesAndMessages%
});

});";

	}
}
